//=============================================================================
/**
 * @file	comm_field_state.c
 * @brief	通信状態を管理するサービス  通信の上位にある
 *          スレッドのひとつとして働き、自分の通信状態や他の機器の
 *          開始や終了を管理する
 *          フィールド上で直接管理したいのでcommunicationからfieldに移動 2005.09.28
 * @author	Katsumi Ohno
 * @date    2005.08.02
 */
//=============================================================================

#include "common.h"
#include "communication/communication.h"
#include "communication/comm_state.h"
#include "system/gamedata.h"
#include "system/pm_str.h"

#include "comm_field_state.h"
#include "comm_player.h"
#include "field/field.h"
#include "fieldsys.h"
#include "comm_command_field.h"
#include "comm_direct_counter.h"
#include "comm_vsroom.h"
#include "sysflag.h"

#include "script.h"							//StartFieldScript
#include "..\fielddata\script\common_scr_def.h"		//SCRID_TRAINER_MOVE_SCRIPT
#include "..\fielddata\script\connect_def.h"		//SCRID_CONNECT_COLOSSEUM
#include "../fielddata/script/battle_room_def.h"
#include "savedata/trainercard_data.h"
#include "application/trainer_card.h"
#include "tr_card_setup.h"
#include "system/wipe.h"
#include "system/pm_overlay.h"
#include "system/brightness.h"

#include "field/union_beacon_tool.h"
#include "field_encount.h"

#ifdef PM_DEBUG
#include "d_ohno.h"
#include "fld_debug.h"
#endif
//==============================================================================
//	型宣言
//==============================================================================
// コールバック関数の書式
typedef void (*PTRStateFunc)(void);

#define _TRAINER_CARD_NUM_MAX (4)

//==============================================================================
// ワーク
//==============================================================================

typedef struct{
    TR_CARD_DATA* pTRCard[_TRAINER_CARD_NUM_MAX];  // トレーナーカードを受信するバッファのポインタ
    u8 bTRCard[_TRAINER_CARD_NUM_MAX];
//    COMM_MESSAGE* pCMess;
    FIELDSYS_WORK* pFSys;
    MATHRandContext32 sRand; ///< 親子機ネゴシエーション用乱数キー
    PTRStateFunc state;
    TCB_PTR pTcb;
    u16 timer;
    u8 connectIndex;   // 子機が接続する親機のindex番号
    u8 bStalth;
    u8 bStateNoChange;
    u8 bUGOverlay;
    u8 bReturnBattle; // バトルから戻ってきた場合は１ 入ってきた場合は０
    u8 bBattleMoveRoom; // 開始位置についたことを受信

    POKEPARTY*  party;	// ミックスバトル用パーティ

#ifdef PM_DEBUG		// Debug ROM
    u16 debugTimer;
#endif
} _COMM_FSTATE_WORK;

static _COMM_FSTATE_WORK* _pCommFState = NULL;  ///<　ワーク構造体のポインタ

//==============================================================================
// 定義
//==============================================================================
#define _START_TIME (50)     // 開始時間
#define _CHILD_P_SEARCH_TIME (12) ///子機として親を探す時間
#define _PARENT_WAIT_TIME (40) ///親としてのんびり待つ時間
#define _FINALIZE_TIME (2)
#define _EXIT_SENDING_TIME (5)
#define _PARENT_END_TIME (2)
#define _SEND_NAME_TIME (10)
#define _PARENTSCAN_PA (3)  // 親機として検索する確立は1/3

#define _TCB_COMMCHECK_PRT   (10)    ///< フィールドを歩く通信の監視ルーチンのPRI


//==============================================================================
// static宣言
//==============================================================================

// ステートの初期化

static void _commStateInitialize(FIELDSYS_WORK* pFSys);  // 初期化
static void _commCheckFunc(TCB_PTR tcb, void* work);  // ステートを実行しているタスク
static void _changeState(PTRStateFunc state, int time);  // ステートを変更する
static void _changeStateDebug(PTRStateFunc state, int time, int line);  // ステートを変更する

#ifdef PM_DEBUG
#if 1
#define   _CHANGE_STATE(state, time)  _changeStateDebug(state, time, __LINE__)
#else
#define   _CHANGE_STATE(state, time)  _changeState(state, time)
#endif
#else  //PM_DEBUG
#define   _CHANGE_STATE(state, time)  _changeState(state, time)
#endif //PM_DEBUG




// バトル関連ステート
static void _battleParentInit(void);     // 戦闘用親機として初期化
static void _battleParentWaiting(void);  // 戦闘用親機として待機中

static void _battleChildInit(void);     // 戦闘用子機として初期化
static void _battleChildBconScanning(void);  // 戦闘用子機として親機選択中
static void _battleChildConnecting(void);  // 接続許可もらい中
static void _battleChildSendName(void);  // 自分の名前をみんなに送信
static void _battleChildWaiting(void);  // ダイレクト用子機待機中
static void _battleMoveRoomEnter(void); // 戦闘前の部屋に入って待機中
static void _battleMoveRoomEnter2(void); // 戦闘前の部屋に入って待機中
static void _battleMoveRoomReturn(void); // 戦闘前の部屋に入って待機中
static void _battleMoveRoomReturn2(void); // 戦闘前の部屋に入って待機中
static void _battleMoveRoomReturn3(void); // 戦闘前の部屋に入って待機中
static void _battleMoveRoomWait(void);
static void _battleMoveRoom(void); // 戦闘前の部屋に入って待機中
static void _battleChildReTry(void);   // 子機を中断
static void _battleChildReInit(void);   // 子機を再起動
static void _battleMoveRoomEnd_Tim(void);   //バトルルーム終了 戦闘開始
static void _battleMoveRoomEnd(void);   //バトルルーム終了 戦闘開始
static void _battleQuit(void);   //バトルルーム強制終了
static void _trCardCopyEnd(void);
static void _dsChangeTiming(void);
static void _trCardCopyStart(void);
static void _dsChangeEndWaitStart(void);
static void _dsChangeEndWaitEnd(void);

// その他一般的なステート
static void _stateNone(void);            // 何もしない
static void _stateConnectError(void);    // 接続エラー状態
static void _stateEnd(void);             // 終了処理
static void _stateConnectEnd(void);      // 切断処理開始
static void _directEndTiming(void);
static void _directEndNoTiming(void);
static void _stateConnectAutoEnd(void);  // 自動切断処理開始
static void _underChildRebootFunc(void);

#ifdef PM_DEBUG		// Debug ROM
static void _debugTimerStart(void);   // デバッグ用
static void _debugTimerDisp(char* msg);
#else
static void _debugTimerStart(void){}   // デバッグ用
static void _debugTimerDisp(char* msg){}
#endif


//==============================================================================
/**
 * 通信管理ステートの初期化処理
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _commStateInitialize(FIELDSYS_WORK* pFSys)
{
    void* pWork;

    if(_pCommFState!=NULL){   // すでに動作中の場合必要ない
        return;
    }
    CommCommandFieldInitialize((void*)pFSys);
    // 初期化
    _pCommFState = (_COMM_FSTATE_WORK*)sys_AllocMemory(HEAPID_COMMUNICATION, sizeof(_COMM_FSTATE_WORK));
    MI_CpuFill8(_pCommFState, 0, sizeof(_COMM_FSTATE_WORK));
//    _pCommFState->state = NULL;   // 何もしない
    _pCommFState->timer = _START_TIME;
    _pCommFState->pTcb = TCB_Add(_commCheckFunc, NULL, _TCB_COMMCHECK_PRT);
    _pCommFState->pFSys = pFSys;
    _pCommFState->party = NULL;
//    _pCommFState->bStalth = FALSE;
//    _pCommFState->bUGOverlay = FALSE;
//    _pCommFState->bStateNoChange = FALSE;
    _debugTimerStart();
    CommRandSeedInitialize(&_pCommFState->sRand);
}

//==============================================================================
/**
 * 通信管理ステートの終了処理
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _stateFinalize(void)
{
    void* pWork;
    int i;

    if(_pCommFState==NULL){  // すでに終了している
        return;
    }
    TCB_Delete(_pCommFState->pTcb);

    for(i = 0;i < _TRAINER_CARD_NUM_MAX; i++){
        if(_pCommFState->pTRCard[i]){
            sys_FreeMemoryEz(_pCommFState->pTRCard[i]);
        }
//        sys_DeleteHeap(HEAPID_VSROOM);
    }

    if( _pCommFState->party )
    {
		sys_FreeMemoryEz( _pCommFState->party );
	}

    sys_FreeMemoryEz(_pCommFState);
//    sys_DeleteHeap(HEAPID_COMMUNICATION);
    _pCommFState = NULL;
}


//==============================================================================
/**
 * バトル時の親としての通信処理開始
 * @param   serviceNo  通信サービス番号
 * @retval  none
 */
//==============================================================================

void CommFieldStateEnterBattleParent(FIELDSYS_WORK* pFSys, int serviceNo, int regulationNo)
{
    if(CommIsInitialize()){
        return;      // つながっている場合今は除外する
    }
#ifdef PM_DEBUG
    CommStateEnterBattleParent(GameSystem_GetSaveData(pFSys), serviceNo, regulationNo, pFSys->regulation,FALSE, SOLO_DEBUG_NO);
#else
    CommStateEnterBattleParent(GameSystem_GetSaveData(pFSys), serviceNo, regulationNo, pFSys->regulation,FALSE);
#endif
    _commStateInitialize(pFSys);
    _CHANGE_STATE(_battleParentInit, 0);
}

//==============================================================================
/**
 * バトル時の子としての通信処理開始
 * @param   serviceNo  通信サービス番号
 * @retval  none
 */
//==============================================================================

void CommFieldStateEnterBattleChild(FIELDSYS_WORK* pFSys, int serviceNo, int regulationNo)
{
    if(CommIsInitialize()){
        return;      // つながっている場合今は除外する
    }
    // 通信ヒープ作成
#ifdef PM_DEBUG
    CommStateEnterBattleChild(GameSystem_GetSaveData(pFSys), serviceNo, regulationNo,pFSys->regulation, FALSE, SOLO_DEBUG_NO);
#else
    CommStateEnterBattleChild(GameSystem_GetSaveData(pFSys), serviceNo, regulationNo,pFSys->regulation, FALSE);
#endif
    _commStateInitialize(pFSys);
    _CHANGE_STATE(_battleChildInit, 0);
}

//==============================================================================
/**
 * バトル時の子としての通信処理開始
 * @param   connectIndex 接続する親機のIndex
 * @retval  none
 */
//==============================================================================

void CommFieldStateConnectBattleChild(int connectIndex)
{
    _pCommFState->connectIndex = connectIndex;
    _CHANGE_STATE(_battleChildConnecting, 0);
}

//==============================================================================
/**
 * バトル時の子としての通信再起動処理
 * @param   none
 * @retval  none
 */
//==============================================================================

void CommFieldStateRebootBattleChild(void)
{
    _CHANGE_STATE(_battleChildReTry, 0);
}

//==============================================================================
/**
 * バトル時に移動できる部屋に入る時の処理
 * @param   none
 * @retval  none
 */
//==============================================================================

void CommFieldStateEnterBattleRoom(FIELDSYS_WORK* pFSys)
{
    OHNO_PRINT("部屋に入った\n");
    WIPE_SetWndMask(WIPE_DISP_MAIN,WIPE_FADE_BLACK);
    WIPE_SetWndMask(WIPE_DISP_SUB,WIPE_FADE_BLACK);
    CommStateSetErrorCheck(TRUE,TRUE);

    if(!CommStateIsInitialize()){  // 通信状態で無いなら終わり
        return;
    }
    if(_pCommFState==NULL){// 動いてない場合動作させる
        _commStateInitialize(pFSys);
        _pCommFState->bReturnBattle = TRUE;
    }
    else{
        _pCommFState->bReturnBattle = FALSE;
    }
    _pCommFState->bBattleMoveRoom = FALSE;

    {  // トレーナーカードのデータ準備
        int i,id = CommGetCurrentID();
        MYSTATUS *my_st = CommInfoGetMyStatus(CommGetCurrentID());
        for(i = 0; i < CommGetConnectNum(); i++){
            if(_pCommFState->pTRCard[i]==NULL){
                _pCommFState->pTRCard[i] = sys_AllocMemory(HEAPID_BASE_SYSTEM,sizeof(TR_CARD_DATA));
            }
        }
        TRCSET_MakeTrainerInfo( BADGE_BRUSH_OFF, TIME_UPDATE_OFF, GYM_READER_MASK_NONE, UNION_TR_NONE,
//                                UnionView_GetTrainerInfo( MyStatus_GetMySex(my_st),
//                                                          MyStatus_GetTrainerView(my_st), UNIONVIEW_ICONINDEX ),
                                _pCommFState->pFSys,
                                _pCommFState->pTRCard[id] );
    }
    CommTimingSyncStart(DBC_TIM_BATTLE_TR);
    _CHANGE_STATE(_trCardCopyStart, 0);
}

//==============================================================================
/**
 * データコピーが終わったかどうか
 * @param   none
 * @retval  none
 */
//==============================================================================

BOOL CommFieldStateIsCopyEnd(void)
{
    if(_pCommFState->state == _trCardCopyStart){
        return FALSE;
    }
    if(_pCommFState->state == _trCardCopyEnd){
        return FALSE;
    }
    return TRUE;
}

//==============================================================================
/**
 * バトル時の通信処理終了手続き
 * @param   none
 * @retval  none
 */
//==============================================================================

void CommFieldStateExitBattle(void)
{
    if(_pCommFState==NULL){
        return;      // すでに終了している場合は除外
    }
    CommStateSetErrorCheck(FALSE,FALSE);
    _CHANGE_STATE(_directEndNoTiming, _EXIT_SENDING_TIME);
}


//==============================================================================
/**
 * バトル時の通信処理終了手続き  最後に同期を取って終了
 * @param   none
 * @retval  none
 */
//==============================================================================

void CommFieldStateExitBattleTiming(void)
{
    if(_pCommFState==NULL){
        return;      // すでに終了している場合は除外
    }
    CommTimingSyncStart(DBC_TIM_BATTLE_EXIT2);
    _CHANGE_STATE(_directEndTiming, _EXIT_SENDING_TIME);
}




//==============================================================================
/**
 * 通信管理ステートの処理
 * @param
 * @retval  none
 */
//==============================================================================

void _commCheckFunc(TCB_PTR tcb, void* work)
{
#ifdef PM_DEBUG
    _pCommFState->debugTimer++;
#endif

    if(_pCommFState==NULL){
        TCB_Delete(tcb);
    }
    else{
        if(_pCommFState->state != NULL){
            PTRStateFunc state = _pCommFState->state;
            if(!_pCommFState->bStateNoChange){
                state();
            }
        }
    }
}

//==============================================================================
/**
 * 通信管理ステートの変更
 * @param   state  変えるステートの関数
 * @param   time   ステート保持時間
 * @retval  none
 */
//==============================================================================

static void _changeState(PTRStateFunc state, int time)
{
    _pCommFState->state = state;
    _pCommFState->timer = time;
}

#ifdef PM_DEBUG
static void _changeStateDebug(PTRStateFunc state, int time, int line)
{
    OHNO_PRINT("CF field_state: %d %d\n",line, CommGetCurrentID());
    _changeState(state, time);
}
#endif


//==============================================================================
/**
 * 親機として初期化を行う
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleParentInit(void)
{
    if(!CommIsConnect(CommGetCurrentID())){
//    if(!CommIsVRAMDInitialize()){
        return;
    }
    CommChildListWindowOpen();
    CommInfoSendPokeData();
    _CHANGE_STATE(_battleParentWaiting, 0);
}

//==============================================================================
/**
 * 親機として待機中
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleParentWaiting(void)
{
  //  if(CommGetCurrentID() == COMM_PARENT_ID){
    //    CommInfoSendArray_ServerSide();  // 子機から問い合わせがあったらinfoを送信
   // }
}

//==============================================================================
/**
 * 子機の初期化
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildInit(void)
{
    if(!CommIsVRAMDInitialize()){
        return;
    }

    CommParentSelectParentWindowOpen();
    _CHANGE_STATE(_battleChildBconScanning, 0);
}

//==============================================================================
/**
 * 子機待機状態  親機ビーコン収集中
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildBconScanning(void)
{
//    CommParentBconCheck();
}

//==============================================================================
/**
 * 子機待機状態  親機に許可もらい中
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildConnecting(void)
{
    CommStateConnectBattleChild(_pCommFState->connectIndex);
    _CHANGE_STATE(_battleChildSendName, 0);
}

//==============================================================================
/**
 * 子機待機状態  親機に情報を送信
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildSendName(void)
{
    if(!CommIsBattleConnectingState()){
        return;
    }
    CommInfoSendPokeData();
    _CHANGE_STATE(_battleChildWaiting, 0);
}

//==============================================================================
/**
 * 子機待機状態
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildWaiting(void)
{
    //Exitを受け取ったら子機切断
}



//==============================================================================
/**
 * 子機enter状態  移動ルーム内に戻ってきた
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomReturn(void)
{
    void* pWork;
    if(CommIsTimingSync(DBC_TIM_BATTLE_DSEND)){
        pWork = sys_AllocMemory(HEAPID_COMMUNICATION, CommPlayerGetWorkSize());
        CommPlayerManagerInitialize(pWork, _pCommFState->pFSys, FALSE);
        CommPlayerFirstMoveEnable();
        CommDisableSendMoveData();  // 移動禁止
        CommTimingSyncStart(DBC_TIM_BATTLE_PAUSE);
        _CHANGE_STATE(_battleMoveRoomReturn2, 0);
        return;
    }
    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
    }
    else{
        _pCommFState->timer=30;
        CommTimingSyncStart(DBC_TIM_BATTLE_DSEND);
    }
}

//==============================================================================
/**
 * 子機待機状態  移動ルーム内
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomReturn2(void)
{
    if(CommGetCurrentID() == COMM_PARENT_ID){
        CommInfoSendArray_ServerSide();  // 子機から問い合わせがあったらinfoを送信
    }
    if(CommIsTimingSync(DBC_TIM_BATTLE_PAUSE)){

        WIPE_SYS_Start(
            WIPE_PATTERN_WMS, WIPE_TYPE_FADEIN,
            WIPE_TYPE_FADEIN, WIPE_FADE_BLACK, COMM_BRIGHTNESS_SYNC, 1, HEAPID_FIELD );

        WIPE_ResetWndMask(WIPE_DISP_MAIN);
        WIPE_ResetWndMask(WIPE_DISP_SUB);

        CommPlayerManagerReboot();
        CommPlayerSendPos(FALSE);
        _CHANGE_STATE(_battleMoveRoomReturn3,1);
    }
}

static void _battleMoveRoomReturn4(void)
{
    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    if(CommIsTimingSync(DBC_TIM_BATTLE_BACK)){
        CommEnableSendMoveData();  // 移動OK
        _CHANGE_STATE(_battleMoveRoomWait,0);
    }
}


static void _battleMoveRoomReturn3(void)
{
    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    if(CommGetCurrentID() == COMM_PARENT_ID){
        if(FALSE == CommPlayerMoveBattlePos()){
            return;
        }
        CommTimingSyncStart(DBC_TIM_BATTLE_BACK);
    }
    else{
        CommTimingSyncStart(DBC_TIM_BATTLE_BACK);
    }
    _CHANGE_STATE(_battleMoveRoomReturn4,20);
}


//==============================================================================
/**
 * 子機enter状態  移動ルーム内にはいってきた
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomEnter(void)
{
    void* pWork;

    if(CommIsTimingSync(DBC_TIM_BATTLE_DSEND)){
        pWork = sys_AllocMemory(HEAPID_COMMUNICATION, CommPlayerGetWorkSize());
        CommPlayerManagerInitialize(pWork, _pCommFState->pFSys, FALSE);
        CommPlayerFirstMoveEnable();
        CommTimingSyncStart(DBC_TIM_BATTLE_PAUSE);
        _CHANGE_STATE(_battleMoveRoomEnter2, 0);
        return;
    }

    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
    }
    else{
        _pCommFState->timer=30;
        CommTimingSyncStart(DBC_TIM_BATTLE_DSEND);
    }

}

//==============================================================================
/**
 * 子機待機状態  移動ルーム内
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomEnter2(void)
{
    if(CommGetCurrentID() == COMM_PARENT_ID){
        CommInfoSendArray_ServerSide();  // 子機から問い合わせがあったらinfoを送信
    }
    if(CommIsTimingSync(DBC_TIM_BATTLE_PAUSE)){
        CommPlayerManagerReboot();
        CommPlayerSendPos(FALSE);
        {
            u8 bit = TRUE;
            CommSendFixSizeData(CF_DIRECT_START_SET,&bit);
        }

        WIPE_SYS_Start(
            WIPE_PATTERN_WMS, WIPE_TYPE_FADEIN,
            WIPE_TYPE_FADEIN, WIPE_FADE_BLACK, COMM_BRIGHTNESS_SYNC, 1, HEAPID_FIELD );
        WIPE_ResetWndMask(WIPE_DISP_MAIN);
        WIPE_ResetWndMask(WIPE_DISP_SUB);

        _CHANGE_STATE(_battleMoveRoom,0);
    }
}


static void _exitCheck(void)
{
    int i,k;

    for(i = 0;i < CommGetConnectNum();i++){
        if(i != CommGetCurrentID()){
            if(CommGetTimingSyncNo(i) == DBC_TIM_BATTLE_EXIT){
                if((_pCommFState->pFSys->event==NULL) && (_pCommFState->pFSys->sublcd_menu_on==FALSE)){
                    for(k = 0;k < _TRAINER_CARD_NUM_MAX; k++){
                        if(_pCommFState->pTRCard[k]){
                            sys_FreeMemoryEz(_pCommFState->pTRCard[k]);
                            _pCommFState->pTRCard[k]=NULL;
                        }
                    }
                    EventSet_Script( _pCommFState->pFSys, SCRID_BATTLE_ROOM_FORCEEND, NULL );
                }
            }
        }
    }
    CommErrorCheck(HEAPID_FIELD,_pCommFState->pFSys->bgl);
}


//==============================================================================
/**
 *  移動ルーム内  キャンセルしたか、全員そろったかのコールバック
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomWait(void)
{
    if(!CommPlayerCheckBattleJump()){
        _pCommFState->bBattleMoveRoom = FALSE;
        {
            u8 bit = TRUE;
            CommSendFixSizeData(CF_DIRECT_START_SET,&bit);
        }
        _CHANGE_STATE(_battleMoveRoom, 0);
    }
    _exitCheck();  // 一斉に終了する検査
}

// スタートライン時の終了コールバック
static void _startLineCallBack(BOOL bStart, const POKEPARTY* party)
{
	if( party )
	{
		_pCommFState->party = PokeParty_AllocPartyWork( HEAPID_WORLD );
		PokeParty_Copy( party, _pCommFState->party );
    }

    if(bStart){
        _CHANGE_STATE(_battleMoveRoomEnd_Tim, 3);
    }
    else{  // もういちど動く場合
        {
            u8 bit = 3;
            CommSendFixSizeData(CF_DIRECT_START_SET,&bit);
        }
        _CHANGE_STATE(_battleMoveRoomWait, 0);
    }
}

//==============================================================================
/**
 * 子機待機状態  移動ルーム内
    回転させて待機イベント起動
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomNop(void)
{
    // スタートラインコールバックの返事を待つ
    _CHANGE_STATE(_battleMoveRoomWait,0);
}


static void _battleMoveRoomEventSet(void)
{
    if(CommSysIsMoveKey() || (0 != CommPlayerGetWalkCount(CommGetCurrentID()))){
        return;
    }

    if(_pCommFState->timer != 0){
        _pCommFState->timer--;
        return;
    }
    CommPlayerHold();
    EventCmd_StartLine(_pCommFState->pFSys, _startLineCallBack);

    _CHANGE_STATE(_battleMoveRoomNop,0);
}

//==============================================================================
/**
 * 子機待機状態  移動ルーム内
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoom(void)
{
    if( _pCommFState->bBattleMoveRoom ){  // 開始位置についたことを受信
        _CHANGE_STATE(_battleMoveRoomEventSet, 5);  // 移動、スタートラインイベント
        {
            u8 bit = FALSE;
            CommSendFixSizeData(CF_DIRECT_START_SET,&bit);
        }
    }
    _exitCheck();
}

//CF_DIRECT_STARTPOS
void CommDirectRecvStartPos(int netID, int size, void* pData, void* pWork)
{
    u8* pBuff = pData;

    if(pBuff[0] == CommGetCurrentID()){
        _pCommFState->bBattleMoveRoom = TRUE;
    }
}

BOOL CommDirectIsMoveState(void)
{
    if(_pCommFState ){
        if((_pCommFState->state == _battleMoveRoom) ||
           (_pCommFState->state == _battleMoveRoomWait)){
            return TRUE;
        }
    }
    return FALSE;
}

//==============================================================================
/**
 * 子機待機状態  移動ルーム内
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomEnd(void)
{
    BOOL bDSMode = TRUE;
    int type;
    u8 sel[6];

    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    type = FIGHT_TYPE_1vs1_SIO;
    switch(CommStateGetServiceNo()){
      case COMM_MODE_BATTLE_MULTI:
      case COMM_MODE_BATTLE_MIX_2ON2:
        type = FIGHT_TYPE_MULTI_SIO;
        break;
      case COMM_MODE_BATTLE_DOUBLE:
      case COMM_MODE_BATTLE_DOUBLE_FLAT:
        type = FIGHT_TYPE_2vs2_SIO;
        break;
    }
    CommStateGetPokemon(sel);

	if( _pCommFState->party == NULL )
	{
		EventSet_CommDirectBattle(_pCommFState->pFSys,sel, type);
	}
	else
	{
		EventSet_CommDirectMixBattle( _pCommFState->pFSys, _pCommFState->party, type );
		sys_FreeMemoryEz( _pCommFState->party );
		_pCommFState->party = NULL;
	}

//    EventSet_Script( _pCommFState->pFSys, SCRID_CONNECT_COLOSSEUM_BATTLE_START, NULL );
//    CommPlayerManagerFinalize(FALSE);
//    CommSendFixSizeData(CS_DSMP_CHANGE, &bDSMode);  //バトルモードに変更する
    _stateFinalize();
}



//==============================================================================
/**
 * 子機待機状態  移動ルーム内
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomEnd_4(void)
{
    if(CommIsTransmissonDSType()){
        if(_pCommFState->timer!=0){
            _pCommFState->timer--;
        }
        if(_pCommFState->timer  == 90){
            CommTimingSyncStart(DBC_TIM_BATTLE_DSOK);
        }
        if(CommIsTimingSync(DBC_TIM_BATTLE_DSOK)){
            _CHANGE_STATE(_battleMoveRoomEnd,0);
        }
    }
}

//==============================================================================
/**
 * 子機待機状態  移動ルーム内
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomEnd_3(void)
{
    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    CommSetTransmissonTypeDS();
    _CHANGE_STATE(_battleMoveRoomEnd_4,120);
}

//==============================================================================
/**
 * 子機待機状態  移動ルーム内
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomEnd_2(void)
{
    BOOL bDSMode = TRUE;

    if(CommIsTimingSync(DBC_TIM_BATTLE_MPDS)){
//        if(CommGetCurrentID() == COMM_PARENT_ID){
//            CommSendFixSizeData(CS_DSMP_CHANGE, &bDSMode);  //バトルモードに変更する
//        }
        _CHANGE_STATE(_battleMoveRoomEnd_3,2);
    }
}

//==============================================================================
/**
 * 子機待機状態  移動ルーム内
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleMoveRoomEnd_Tim(void)
{
    BOOL bDSMode = TRUE;

    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    CommPlayerManagerFinalize(FALSE);
    CommTimingSyncStart(DBC_TIM_BATTLE_MPDS);
    _CHANGE_STATE(_battleMoveRoomEnd_2,0);
}

//==============================================================================
/**
 * エラーによるバトルの強制終了
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleQuit(void)
{
}

//==============================================================================
/**
 * 子機をいったん終了
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildReTry(void)
{
    CommStateRebootBattleChild();
    _CHANGE_STATE(_battleChildReInit, _FINALIZE_TIME);
}

//==============================================================================
/**
 * 子機をいったん終了し再起動をかける
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildReInit(void)
{
    if(!CommMPIsStateIdle()){  /// 終了処理がきちんと終わっていることを確認
        return;
    }
    _CHANGE_STATE(_battleChildSendName, _SEND_NAME_TIME);
}






void CommDCRecvTrainerCard(int netID ,int size, void* pBuff, void* pWork )
{
    OHNO_SP_PRINT("CommDCRecvTrainerCard %d\n",netID);
    _pCommFState->bTRCard[netID] = TRUE;
}

u8* CommDCGetTrainerCardRecvBuff( int netID, void* pWork, int size)
{
    GF_ASSERT_RETURN(netID < _TRAINER_CARD_NUM_MAX,NULL);
    return (u8*)_pCommFState->pTRCard[netID];
}





//==============================================================================
/**
 * データシェアリング中にトレーナーカードをコピーしあう
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _trCardCopyStart(void)
{
    int i,id = CommGetCurrentID();

    if(CommIsTimingSync(DBC_TIM_BATTLE_TR)){
        CommSendHugeData(CF_TRAINER_CARD, _pCommFState->pTRCard[id], sizeof(TR_CARD_DATA));
        _CHANGE_STATE(_trCardCopyEnd,0);
    }
}

//==============================================================================
/**
 * データシェアリング中にトレーナーカードをコピーしあう
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _trCardCopyEnd(void)
{
    int i;

    for(i = 0; i < CommGetConnectNum(); i++){
        if(!_pCommFState->bTRCard[i]){
            return;
        }
    }
    CommTimingSyncStart(DBC_TIM_BATTLE_DSCHANGE);
    _CHANGE_STATE(_dsChangeTiming,0);
}


static void _dsChangeEndWaitStart_3(void)
{

    if(!CommIsTransmissonDSType()){
        if(_pCommFState->timer!=0){
            _pCommFState->timer--;
        }
        if(_pCommFState->timer  == 90){
            CommTimingSyncStart(DBC_TIM_BATTLE_MPOK);
        }
        if(CommIsTimingSync(DBC_TIM_BATTLE_MPOK)){
            _CHANGE_STATE(_dsChangeEndWaitStart,0);
        }
    }


}


static void _dsChangeEndWaitStart_2(void)
{
    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    CommSetTransmissonTypeMP();
    _CHANGE_STATE(_dsChangeEndWaitStart_3,120);
}

static void _dsChangeTiming(void)
{
    if(CommIsTimingSync(DBC_TIM_BATTLE_DSCHANGE)){
        _CHANGE_STATE(_dsChangeEndWaitStart_2,2);
    }
}

static void _dsChangeEndWaitStart(void)
{
    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    CommTimingSyncStart(DBC_TIM_BATTLE_DSEND);
    if(_pCommFState->bReturnBattle){
        _CHANGE_STATE(_battleMoveRoomReturn, 30);
    }
    else{
        _CHANGE_STATE(_battleMoveRoomEnter, 30);
    }
}


//==============================================================================
/**
 * 何もしないステート
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _stateNone(void)
{
    // なにもしていない
}

//==============================================================================
/**
 * @brief エラー処理
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _stateConnectError(void)
{
}

//==============================================================================
/**
 * @brief  終了処理中
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _stateEnd(void)
{
    if(CommIsInitialize()){
        return;
    }
    _stateFinalize();
}

//==============================================================================
/**
 * @brief  地下離脱処理開始
 * @param   none
 * @retval  none
 */
//==============================================================================
#if 0
static void _stateUnderGroundConnectEnd(void)
{
    if(_pCommFState->timer != 0){
        _pCommFState->timer--;
        return;
    }

    CommUnderOptionFinalize();
    CommStateExitUnderGround();

    sys_DeleteHeap(HEAPID_UNDERGROUND);

    _pCommFState->bUGOverlay = FALSE; // 地下を止める

    _stateFinalize();   // stateはここで終了 通信は後から切れる
}
#endif
//==============================================================================
/**
 * @brief  自動終了処理開始
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _directEndTiming(void)
{
    if(CommIsTimingSync(DBC_TIM_BATTLE_EXIT2)){
        CommStateSetErrorCheck(FALSE,FALSE);
        OHNO_PRINT("終了同期を取った---\n");
        CommPlayerManagerFinalize(TRUE);
        _CHANGE_STATE(_stateConnectAutoEnd, _EXIT_SENDING_TIME);
    }
}

//==============================================================================
/**
 * @brief  自動終了処理開始
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _directEndNoTiming(void)
{
    CommPlayerManagerFinalize(TRUE);
    _CHANGE_STATE(_stateConnectAutoEnd, _EXIT_SENDING_TIME);
}

//==============================================================================
/**
 * @brief  自動終了処理開始
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _stateConnectAutoEnd(void)
{
    if(_pCommFState->timer != 0){
        _pCommFState->timer--;
        return;
    }
//    if(CommIsConnect(CommGetConnectNum())){
//        CommSendFixData(CS_AUTO_EXIT);
  //  }
    //else{
        CommStateExitBattle();
        _CHANGE_STATE(_stateFinalize, 0);
   // }
}

//==============================================================================
/**
 * @brief  終了処理開始
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _stateConnectEnd(void)
{
    if(_pCommFState->timer != 0){
        _pCommFState->timer--;
        return;
    }
    // 切断する
    CommFinalize();
    _CHANGE_STATE(_stateEnd, 0);
}

#ifdef PM_DEBUG
static void _debugTimerStart(void)
{
    _pCommFState->debugTimer=0;
}

static void _debugTimerDisp(char* msg)
{
    OHNO_PRINT("%s 開始から %d sync かかりました\n", msg, _pCommFState->debugTimer * 2);
}

#endif


#ifdef PM_DEBUG


static BOOL GMEVENT_BattleDebug(GMEVENT_CONTROL * event)
{
    if(CommIsInitialize()){
        return FALSE;
    }
    return TRUE;
}

//==============================================================================
/**
 * 子機待機状態  親機に情報を送信
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildWaiting_Debug(void)
{

    OHNO_PRINT("接続検査中 CommGetConnectNum=%d CommMPGetServiceNo=%d \n",CommGetConnectNum(),CommStateGetServiceNo() );
    if(CommGetConnectNum() == (CommGetMaxEntry(CommStateGetServiceNo()))){
        CommDirectConnect_Debug();
        _CHANGE_STATE(_battleChildWaiting, 0);
    }
}

//==============================================================================
/**
 * 子機待機状態  親機に情報を送信
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildSendName_Debug(void)
{
    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    if(!CommIsConnect(CommGetCurrentID())){
        return;
    }
    CommInfoSendPokeData();
    _CHANGE_STATE(_battleChildWaiting_Debug, 0);
}

//==============================================================================
/**
 * 子機待機状態  親機に許可もらい中（デバッグ）
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleChildConnecting_Debug(void)
{
    if(CommMPGetGFBss(_pCommFState->connectIndex)!=NULL){
        CommStateConnectBattleChild(_pCommFState->connectIndex);  // 接続
        _CHANGE_STATE(_battleChildSendName_Debug, _SEND_NAME_TIME);
    }
}

//==============================================================================
/**
 * バトル時の子としての通信処理開始
 * @param   connectIndex 接続する親機のIndex
 * @retval  none
 */
//==============================================================================

void CommFieldStateConnectBattleChild_Debug( FIELDSYS_WORK* pFSys, int serviceNo, int regulationNo, int connectIndex)
{
    if(CommIsInitialize()){
        return;      // つながっている場合今は除外する
    }
#ifdef PM_DEBUG
    CommStateEnterBattleChild(GameSystem_GetSaveData(pFSys), serviceNo, regulationNo, pFSys->regulation,FALSE, SOLO_DEBUG_NO + COMMDIRECT_DEBUG_NO);
#else
    CommStateEnterBattleChild(GameSystem_GetSaveData(pFSys), serviceNo, regulationNo, pFSys->regulation,FALSE);
#endif
    _commStateInitialize(pFSys);
    _pCommFState->connectIndex = connectIndex;
    _CHANGE_STATE(_battleChildConnecting_Debug, 0);
}


//==============================================================================
/**
 * 親機として待機中
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleParentWaiting_Debug(void)
{
    if(CommIsChildsConnecting()){
        OHNO_PRINT("接続検査中 CommGetConnectNum=%d CommMPGetServiceNo=%d \n",CommGetConnectNum(),CommStateGetServiceNo() );
        if(CommGetConnectNum() == (CommGetMaxEntry(CommStateGetServiceNo()))){
            CommDirectConnect_Debug();
            _CHANGE_STATE(_battleParentWaiting, 0);
        }
    }
}

//==============================================================================
/**
 * 子機待機状態  親機を選択中
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleParentSendName_Debug(void)
{
    if(_pCommFState->timer!=0){
        _pCommFState->timer--;
        return;
    }
    if(!CommIsConnect(CommGetCurrentID())){
        return;
    }
    CommInfoSendPokeData();
    _CHANGE_STATE(_battleParentWaiting_Debug, 0);
}

//==============================================================================
/**
 * 親機として初期化を行う
 * @param   none
 * @retval  none
 */
//==============================================================================

static void _battleParentInit_Debug(void)
{
    MYSTATUS* pMyStatus;

    if(!CommIsVRAMDInitialize()){
        return;
    }
    _CHANGE_STATE(_battleParentSendName_Debug, _SEND_NAME_TIME);
}

//==============================================================================
/**
 * バトル時の親としての通信処理開始
 * @param   pFSys  フィールド構造体
 * @param   serviceNo  通信サービス番号
 * @param   regulationNo  通信サービス番号
 * @retval  none
 */
//==============================================================================

void CommFieldStateEnterBattleParent_Debug(FIELDSYS_WORK* pFSys, int serviceNo, int regulationNo)
{
    if(CommIsInitialize()){
        return;      // つながっている場合今は除外する
    }
#ifdef PM_DEBUG
    CommStateEnterBattleParent(GameSystem_GetSaveData(pFSys), serviceNo, regulationNo,pFSys->regulation, FALSE,
                               SOLO_DEBUG_NO + COMMDIRECT_DEBUG_NO);
#else
    CommStateEnterBattleParent(GameSystem_GetSaveData(pFSys), serviceNo, regulationNo,pFSys->regulation, FALSE);
#endif
    _commStateInitialize(pFSys);
    _CHANGE_STATE(_battleParentInit_Debug, 0);

}

#endif

//==============================================================================
/**
 * @brief   バトル開始待機中か取得関数追加
 * @param   sv  SAVEDATA*
 * @retval  SECRETBASEDATA*
 */
//==============================================================================
//BTS4761対応
const BOOL CommIsWaitBattleStart(void)
{
  if( _pCommFState == NULL )
  {
    return FALSE;
  }
  else
  {
    if( _pCommFState->state == _battleMoveRoomEnd_Tim ||
        _pCommFState->state == _battleMoveRoomEnd_2 ||
        _pCommFState->state == _battleMoveRoomEnd_3 ||
        _pCommFState->state == _battleMoveRoomEnd_4 ||
        _pCommFState->state == _battleMoveRoomEnd )
    {
      return TRUE;
    }
  }
  return FALSE;
}


//==============================================================================
/**
 * @brief   今からセットアップする秘密基地グッズデータを返す
 * @param   sv  SAVEDATA*
 * @retval  SECRETBASEDATA*
 */
//==============================================================================
#if 0
SECRETBASEDATA* CommUgSetupSecretBaseData(SAVEDATA * sv)
{
    if(!_pCommFState || !_pCommFState->bUGOverlay){
        return NULL;
    }
    return UgManUgSetupSecretBaseData(sv);
}
#endif

#if 0
BOOL CommFieldStateIsUnder(void)
{
    if(_pCommFState && _pCommFState->bUGOverlay){
        return TRUE;
    }
    return FALSE;
}

void CommStateFieldUnderOptionReset(void)
{
    if(_pCommFState && _pCommFState->bUGOverlay){
       // CommSystemRecvStop(TRUE);
    //    OHNO_PRINT("通信止めました\n");
     //   CommUnderOptionReset();
    }
}

void CommStateFieldUnderOptionReboot(void)
{
    if(_pCommFState && _pCommFState->bUGOverlay){
       // CommUnderOptionReboot();
   //    OHNO_PRINT("通信許可しました\n");
       // CommSystemRecvStop(FALSE);
    }
}
#endif